package com.ctrlspace.servlets;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.json.simple.JSONObject;

import com.ctrlspace.core.compiler.AutoComplete;
import com.ctrlspace.core.managers.ProjectManager;
import com.ctrlspace.model.FileUnit;
import com.ctrlspace.model.ProjectUnit;
import com.ctrlspace.model.User;

/**
 * Servlet implementation class ProjectServlet
 */
public class ProjectServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	
	@SuppressWarnings("unchecked")
	private void process(HttpServletRequest request, HttpServletResponse response) {
		HttpSession session = request.getSession();

		// Get parameters
		User currentUser = (User) session.getAttribute("CURRENT_USER");
		String commandString = request.getParameter("command");
		ProjectCommand command = ProjectCommand.find(commandString);

		switch (command) {
			case CREATE:
				// Get additional parameters
				String projectName = request.getParameter("projectName");
				String projectType = request.getParameter("projectType");
				
				try {
					ProjectUnit projectUnit = ProjectManager.getInstance().createProject(currentUser.getId(), projectName, "", projectType, null);
					
					Map obj = new LinkedHashMap();
					obj.put("success", true);
					obj.put("projectId", projectUnit.getProjectId());
					response.getWriter().write(JSONObject.toJSONString(obj));
				} catch (Exception e) {
					e.printStackTrace();
				}
			break;
			
			case OPEN_FILE:
				String relativePath = request.getParameter("filePath");
				int projectId = Integer.parseInt(request.getParameter("projectId"));
				try {
					FileUnit fileUnit = ProjectManager.getInstance().openFile(currentUser.getId(), projectId, relativePath);
					response.getWriter().write(fileUnit.toJSONString());
					return;
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			break;

			case GET:

			break;

			case GET_ALL:
				List<ProjectUnit> projects;
				try {
					projects = ProjectManager.getInstance().getProjects(currentUser.getId());
					
					if (projects == null) {
						projects = new ArrayList<ProjectUnit>();
					}

					Map obj = new LinkedHashMap();
					obj.put("items", projects);
					obj.put("label", "label");
					response.getWriter().write(JSONObject.toJSONString(obj));
				} catch (Exception e) {
					e.printStackTrace();
				}
			break;
			
			case CREATE_FOLDER:
				// Get additional parameters
				
				String folderName = request.getParameter("folderName");
				String folderSourceFile = request.getParameter("sourceFile");
				try {
					ProjectManager.getInstance().addFolder(1, 1, folderName, folderSourceFile);
					
					Map obj = new LinkedHashMap();
					obj.put("success", true);
					response.getWriter().write(JSONObject.toJSONString(obj));
				} catch (Exception e) {
					e.printStackTrace();
				}
			break;
			
			case CREATE_PACKAGE:
				// Get additional parameters
				
				String packageName = request.getParameter("packageName");
				String packageSourceFile = request.getParameter("sourceFile");
				try {
					ProjectManager.getInstance().addFolder(1, 1, packageName, packageSourceFile);
					
					Map obj = new LinkedHashMap();
					obj.put("success", true);
					response.getWriter().write(JSONObject.toJSONString(obj));
				} catch (Exception e) {
					e.printStackTrace();
				}
			break;
			
			case CREATE_ENUM:
				// Get additional parameters
				String enumFileName = request.getParameter("fileName");
				String enumPackageName = request.getParameter("packageName");
				String enumSourceFile = request.getParameter("sourceFile");
				try {
					ProjectManager.getInstance().addEnum(1, 1, enumFileName, enumPackageName);
					
					Map obj = new LinkedHashMap();
					obj.put("success", true);
					response.getWriter().write(JSONObject.toJSONString(obj));
				} catch (Exception e) {
					e.printStackTrace();
				}
			break;
			
			case CREATE_INTERFACE:
				// Get additional parameters
				
				String intFileName = request.getParameter("fileName");
				String intPackageName = request.getParameter("packageName");
				String intSourceFile = request.getParameter("sourceFile");
				try {
					ProjectManager.getInstance().addInterface(1, 1, intFileName, intPackageName);
					
					Map obj = new LinkedHashMap();
					obj.put("success", true);
					response.getWriter().write(JSONObject.toJSONString(obj));
				} catch (Exception e) {
					e.printStackTrace();
				}
			break;
			
			case CREATE_CLASS:
				// Get additional parameters
				
				String classFileName = request.getParameter("fileName");
				String classPackageName = request.getParameter("packageName");
				String classSourceFile = request.getParameter("sourceFile");
				try {
					ProjectManager.getInstance().addClass(1, 1, classFileName, classPackageName);
					
					Map obj = new LinkedHashMap();
					obj.put("success", true);
					response.getWriter().write(JSONObject.toJSONString(obj));
				} catch (Exception e) {
					e.printStackTrace();
				}
			break;
			
			case CREATE_CSS:
				// Get additional parameters
				
				String cssFileName = request.getParameter("fileName");
				String cssFileLocation = request.getParameter("fileLocation");
				try {
					ProjectManager.getInstance().addFile(1, 1, cssFileName + ".css", cssFileLocation);
					
					Map obj = new LinkedHashMap();
					obj.put("success", true);
					response.getWriter().write(JSONObject.toJSONString(obj));
				} catch (Exception e) {
					e.printStackTrace();
				}
			break;
			
			case CREATE_HTML:
				// Get additional parameters
				
				String htmlFileName = request.getParameter("fileName");
				String htmlFileLocation = request.getParameter("fileLocation");
				
				try {
					ProjectManager.getInstance().addFile(1, 1, htmlFileName + ".html", htmlFileLocation);
					
					Map obj = new LinkedHashMap();
					obj.put("success", true);
					response.getWriter().write(JSONObject.toJSONString(obj));
				} catch (Exception e) {
					e.printStackTrace();
				}
			break;
			
			case CREATE_JS:
				// Get additional parameters
				
				String jsFileName = request.getParameter("fileName");
				String jsFileLocation = request.getParameter("fileLocation");
				
				try {
					ProjectManager.getInstance().addFile(1, 1, jsFileName + ".js", jsFileLocation);
					
					Map obj = new LinkedHashMap();
					obj.put("success", true);
					response.getWriter().write(JSONObject.toJSONString(obj));
				} catch (Exception e) {
					e.printStackTrace();
				}
			break;
			
			case AUTO_COMPLETE:
				String codeState = request.getParameter("codeState");
				int lineNumber = Integer.parseInt(request.getParameter("lineNumber"));
				String variableName = request.getParameter("variableName");
				
				AutoComplete autocomplete = new AutoComplete();
				String json;
				try {
					json = autocomplete.getMethods(codeState, lineNumber, variableName);
					response.getWriter().write(json);
				} catch (NumberFormatException e1) {
					e1.printStackTrace();
				} catch (IOException e1) {
					e1.printStackTrace();
				} catch (ClassNotFoundException e1) {
					e1.printStackTrace();
					// TODO Auto-generated catch block
				}
				break;

			case SAVE_FILE:
				String filePath = request.getParameter("filePath");
				String contents = request.getParameter("contents");
				projectId = Integer.parseInt(request.getParameter("projectId"));
				try {
					FileUnit saveFile = ProjectManager.getInstance().saveFile(currentUser.getId(), projectId, filePath, contents);
					response.getWriter().write(saveFile.toJSONString());
				} catch (Exception e) {
					e.printStackTrace();
				}
			break;
			
			case DEPLOY:
				String email = request.getParameter("email");
				String password = request.getParameter("password");
				String applicationId = request.getParameter("applicationId");
				String proxy = request.getParameter("proxy");
				projectId = Integer.parseInt(request.getParameter("projectId"));
			try {
				ProjectManager.getInstance().deployProject(currentUser.getId(), projectId, email, password, applicationId, proxy);
				response.getWriter().write("");
				return;
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			break;
			
			case RUN:
				try {
					projectId = Integer.parseInt(request.getParameter("projectId"));
					Process oldProcess = (Process) session.getAttribute("APPENGINE_PROCESS");

					if (oldProcess != null) {
						oldProcess.destroy();
					}
					Random r = new Random();
					List<Integer> notAllowed = Arrays.asList(0, 21, 80, 8080, 81, 8000, 25, 3306, 22, 23);
					int port = 0;
					while (notAllowed.contains(port)) {
						port = r.nextInt(65000);
					}
					Process p = ProjectManager.getInstance().runProject(currentUser.getId(), projectId, port);
					session.setAttribute("APPENGINE_PROCESS", p);
					
					Thread.sleep(15000);
					
					JSONObject obj = new JSONObject();
					obj.put("success", Boolean.TRUE);
					obj.put("port", port);
					response.getWriter().write(obj.toJSONString());
					return;
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			break;
			
			// Not a valid command
			default:
			break;
		}		
	}

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		process(request, response);
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		process(request, response);
	}

	private enum ProjectCommand {
		OPEN_FILE("open_file"), SAVE_FILE("save_file"),
		ADD_FILE("add"), GET("get"), GET_ALL("get_all"), CREATE("create"), UPDATE("update"), DELETE("delete"),
		CREATE_CLASS("create_class"), CREATE_CSS("create_css"), CREATE_ENUM("create_enum"), CREATE_HTML("create_html"),
		CREATE_JS("create_js"), CREATE_INTERFACE("create_interface"), CREATE_PACKAGE("create_package"), CREATE_FOLDER("create_folder"),
		AUTO_COMPLETE("auto_complete"), DEPLOY("get_deployment_details"), RUN("run");

		String commandString;
		ProjectCommand(String commandString) {
			this.commandString = commandString;
		}

		static HashMap<String, ProjectCommand> commands = new HashMap<String, ProjectCommand>();
		static {
			for (ProjectCommand command : ProjectCommand.values()) {
				if (command.commandString != null) {
					commands.put(command.commandString, command);
				}
			}
		}

		public static ProjectCommand find(String string) {
			return commands.get(string.toLowerCase());
		}
		
		
	}
}
